

#include <windows.h>
#include <GL/gl.h>
#include <GL/glut.h>
#include <iostream>
#include <limits.h>
#define _USE_MATH_DEFINES
#include <math.h>

#include <time.h>

#include "world.h"
#include "box.h"
#include "matrix44.h"
#include "particlefactory.h"
#include "util.h"

float MOVE_RATE[3] = {0.4f, 0.4f, 0.4f};
float ROT_RATE[2] = {0.005f, 0.005f};

float SR = 4.f/3.f;
Vector4 camera = Vector4();
Vector4 pivot = Vector4();
int prevMouseLoc[2] = {INT_MAX, INT_MAX};

bool camControls[3] = {false, false, false};
int TRACKING = 0, ZOOMING = 1, ROTATING = 2;
clock_t firstTick = 0;
float lastTime = (float)firstTick;

World *world;
float anim_angle = 0.0;

void display()
{
	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
	glMatrixMode( GL_PROJECTION );
	glLoadIdentity();
	glOrtho( -100*SR,100*SR, -100,100, -5000,5000);
	glMatrixMode( GL_MODELVIEW );
	glLoadIdentity();

	glPushMatrix();
	//glTranslatef(camera(0),camera(1),camera(2));
	gluLookAt(-camera(0),-camera(1),-camera(2), 
			  -camera(0)+pivot(0),
			  -camera(1)+pivot(1),
			  -camera(2)+pivot(2),
				0.f, 1.f, 0.f);
	world->draw(&camera, &pivot);
	glPopMatrix();

	glutSwapBuffers();
}

void idle()
{
	//anim_angle+=1.f;
	clock_t newTick = clock();
	float elapsed = ((float)newTick - (float)firstTick) / CLOCKS_PER_SEC;
	float etime = elapsed - lastTime;
	//std::cout << "etime: " << etime << std::endl;
	lastTime = elapsed;
	world->update((float)etime);
	
	glutPostRedisplay();
}

void onMouseClick(int button, int state, int x, int y)
{
	if (state==GLUT_DOWN && button<3){
		camControls[button] = true;
		prevMouseLoc[0]=x; prevMouseLoc[1]=y;
	} else if (state==GLUT_UP && button<3)
		camControls[button] = false;
}

void onMouseMove(int x, int y)
{
	int dx = x - prevMouseLoc[0];
	int dy = y - prevMouseLoc[1];
	if (camControls[TRACKING]) {
		pivot.normalize();
		camera(0) -= dx * pivot(0) * MOVE_RATE[0];
		camera(1) -= dy * pivot(1) * MOVE_RATE[1];
		pivot.normalize();
	} if (camControls[ZOOMING]) {
		pivot.normalize();
		camera(2) += dy * MOVE_RATE[2];
	} if (camControls[ROTATING]) {
		pivot(0) -= dx * ROT_RATE[0];
		pivot(1) -= dy * ROT_RATE[1];
		pivot.normalize();
	}
	prevMouseLoc[0]=x; prevMouseLoc[1]=y;
}
void onPassiveMouseMove(int x, int y)
{
}

void onKeyPress(unsigned char key, int x, int y)
{
	if (key==27){
		exit(0);
	}
}

void initGL (int argc, char *argv[])
{
	glutInit( &argc, argv );
	glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH );
	glutInitWindowSize( 800, 600 );
    glutInitWindowPosition( 100, 100 );
    glutCreateWindow( argv[0] );
    glClearColor ( 0.85f, 0.85f, 0.85f, 0.85f );
    glEnable( GL_DEPTH_TEST );
    glShadeModel( GL_SMOOTH );

	glutDisplayFunc( display );
	glutIdleFunc( idle );
	glutMouseFunc(onMouseClick);
	glutMotionFunc(onMouseMove);			   // Any button held
	glutPassiveMotionFunc(onPassiveMouseMove); // No buttons held
	glutKeyboardFunc(onKeyPress);
	camera(0) = 0.f;
	camera(1) = 0.f;
	camera(2) =-3.f;
	pivot(0) =-1.f;
	pivot(1) =-1.f;
	pivot(2) = 1.f;
	pivot.normalize();
}

void startGL()
{
	glutMainLoop();
}

void initWorld()
{
	world = new World();

	Box *b1 = new Box(20,20,20);
	
	Box *b2 = new Box(20,20,20);
	
	world->addBody(b1);
	//world->addBody(b2);
	b1->transformXYZHRPS(0,100,0,0,0,0,1);
	//b2->transformXYZHRPS(-50,11,0,0,0,0,1);

	//b1->aAcc[1]= 1.0; 
	//b2->vel[1]= 10.0; 
	//b2->aVel[0]= .9; 
	//b2->aVel[1]= 1.1;
	//b2->aVel[2]= 1.0;

	ParticleFactory *pf = new ParticleFactory(WATER);
	float pps = 100.f;
	float *rad = new float[3]; rad[0]= 2.f;  rad[1]= 3.f;  rad[2]= 2.f;
	float *pos = new float[3]; pos[0]= 0.f;  pos[1]= 0.f;  pos[2]= 0.f;
	float *spr = new float[3]; spr[0]=20.f;  spr[1]=20.f;  spr[2]=20.f;
	float *vel = new float[3]; vel[0]= 0.f;  vel[1]=50.f;  vel[2]= 0.f;
	float life = 10.f;
	pf->config(pps, rad, pos, spr, vel, life);
	world->addParticleEmitter(pf);
}

int main(int argc, char *argv[])
{
	std::cout << "Running main.cpp" << std::endl;
	
	initWorld();

	initGL(argc, argv);
	startGL();

	return 0;
}
